package cc.mrbird.febs.common.interceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import cc.mrbird.febs.common.annotation.IgnoreToken;
import cc.mrbird.febs.common.entity.FebsConstant;
import cc.mrbird.febs.common.exception.TokenInvalidException;
import cc.mrbird.febs.common.utils.TokenUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Claims;

/**
 * 客户端Token合法性验证拦截器
 *
 * @author Lord
 */
public class ClientTokenInterceptor implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用（Controller方法调用之前）
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        /*
         * 判断是否忽略token的验证 将handler强转为HandlerMethod, 前面已经证实这个handler就是HandlerMethod
         */
        HandlerMethod handlerMethod = (HandlerMethod) handler;

        // 从方法处理器中获取出要调用的方法
        Method method = handlerMethod.getMethod();

        // 获取出方法上的@IgnoreToken注解
        IgnoreToken ignoreToken = method.getAnnotation(IgnoreToken.class);

        // 如果注解不为null, 说明不需要拦截, 直接放过
        if (ObjectUtil.isNull(ignoreToken)) {

            final String token = request.getHeader(FebsConstant.TOKEN);
            if (StrUtil.isEmpty(token)) {
                throw new TokenInvalidException("Token认证出错");
            }

            // 解析jwt token为 map
            Claims claims = TokenUtil.getClaimsByToken(token);

            // 刷新token有效期，原理是重新生成新的token
            String newToken = TokenUtil.refreshToken(claims);

            // 将token保存至header中，传递给前端
            if (StrUtil.isNotEmpty(newToken)) {
                response.setHeader(FebsConstant.TOKEN, newToken);
            } else {
                throw new TokenInvalidException("Token认证出错");
            }
        }

        // 只有返回true才会继续向下执行，返回false取消当前请求
        return true;
    }

    /**
     * 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
            ModelAndView modelAndView) throws Exception {
    }

    /**
     * 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
            Object o, Exception e) throws Exception {
    }

}
